<script setup lang="ts">
import { useBaseApi } from '@/api/base'
import { defineAsyncComponent, computed, ref, onMounted, unref } from 'vue'
import { Edit, Plus, Refresh, Search, Rank, Warning } from '@element-plus/icons-vue'
import type {
  IFListType,
  IFListColumnType,
  BusinessUIQueryType,
  BusinessUIQueryColumnType,
  BusinessUIFormType
} from '@/types/custom'
import { ElMessage } from 'element-plus'
import { formComponents } from '@/utils/custom'
import { useRoute } from 'vue-router'
import { clone, findTree } from 'xe-utils'
import draggable from 'vuedraggable'

// 引入组件
const QueryConfig = defineAsyncComponent(
  () => import('@/views/system/business/query/components/QueryConfig.vue')
)
const JsonEditorDialog = defineAsyncComponent(() => import('@/components/JsonEditorDialog.vue'))

interface Props {
  type: 'query' | 'form'
  labelPosition?: string
}

const props = defineProps<Props>()

defineEmits(['preview'])

const {
  GetIFList,
  GetIFQuery,
  GetBusinessUIForm,
  SaveBusinessUIForm,
  GetBusinessUIQuery,
  SaveBusinessUIQuery
} = useBaseApi()
const route = useRoute()
const { GetBusinessTree } = useBaseApi()

const isSort = ref(false)
const editorRef = ref()
const defaultCol = { xs: 24, sm: 12, md: 6, lg: 6, xl: 4 }
const params = ref<BusinessUIQueryType | BusinessUIFormType>({
  id: '',
  api: '',
  align: '',
  method: '',
  type_name: '',
  default_value: '',
  default_value_parse: {},
  items: []
})
const loading = ref(false)
const keywords = ref('')
const list = ref<IFListType[]>([])
const checked = ref<string>('')
const businessItems = ref<RouteItems>([])

const columns = computed(() => {
  const listItem = list.value.find((f) => f.type_name === checked.value)
  return listItem ? listItem.column : []
})

const loopColumns = computed(() => {
  const search = (keywords.value || '').toLowerCase().trim()
  if (search) {
    return columns.value.filter(
      (f) =>
        f.name.toLowerCase().indexOf(search) !== -1 ||
        f.data_type.toLowerCase().indexOf(search) !== -1
    )
  } else {
    return columns.value
  }
})

/**
 * 是否已选
 * @param column
 */
const isActive = (column: IFListColumnType) => {
  return params.value.items.some((s) => s.field === column.name)
}

/**
 * 新增空字段
 */
const addEmptyColumn = () => {
  addFormColumn({
    field: '',
    title: '',
    name: `empty_${Date.now()}`,
    data_type: 'empty',
    component: '',
    col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24 }
  })
}

/**
 * 添加到表单列
 * @param column
 */
const addFormColumn = (column: IFListColumnType) => {
  const key = column.name.replace('_id', '')
  const arr = [`${key}_name`, `${key}_user`, `${key}_string`]
  if (column.name === 'wf_stauts') {
    arr.push('wf_status_name')
  }
  const col = columns.value.find((f) => arr.includes(f.name))
  const option: BusinessUIQueryColumnType = {
    visible: false,
    required: false,
    field: column.name,
    rel_item: col ? col.name : '',
    default_value: '',
    default_value_parse: {},
    title: '',
    component: column.component || '',
    elComponent: '',
    idx: params.value.items.length,
    set_json: '',
    expand: true,
    set_json_parse: { props: {}, col: column.col || clone(defaultCol, true) }
  }
  const item = findTree(formComponents, (item) => {
    const suffix = item.suffix || []
    const keys = item.keys || []
    return keys.includes(column.name) || suffix.some((s) => new RegExp(s + '$').test(column.name))
  })
  if (item && item.item) {
    // 址引用，防止改原值
    const comp = clone(item.item, true)
    option.component = comp.value
    option.title = comp.title || ''
    option.set_json_parse.props = comp.props
    option.set_json_parse.col = comp.col
    option.elComponent = comp.elComponent
    option.options = comp.options
    const key = comp.suffix?.find((s) => new RegExp(s + '$').test(option.field))
    if (key === '_month') {
      option.title = '月份'
      option.set_json_parse.props.type = 'month'
      option.set_json_parse.props.valueFormat = 'YYYY-MM'
    } else if (key === '_year') {
      option.title = '年份'
      option.set_json_parse.props.type = 'year'
      option.set_json_parse.props.valueFormat = 'YYYY'
    } else if (key === '_time') {
      option.title = '时间'
      option.set_json_parse.props.type = 'datetime'
      option.set_json_parse.props.valueFormat = 'YYYY-MM-DD HH:mm:ss'
    }
  }
  params.value.items.push(option)
}

/**
 * 查询可选字段
 */
const onFetchIFList = () => {
  if (props.type === 'form') {
    GetIFList().then(({ data }) => {
      list.value = data
      if (data.length && !checked.value) {
        checked.value = data[0].type_name
      }
      onFetchData()
    })
  } else {
    GetIFQuery().then(({ data }) => {
      list.value = data
      if (data.length && !checked.value) {
        checked.value = data[0].type_name
      }
      onFetchData()
    })
  }
}

/**
 * 查询
 */
const onFetch = async () => {
  if (props.type === 'form') {
    return GetBusinessUIForm(params.value.id, false)
  } else {
    return GetBusinessUIQuery(params.value.id, false)
  }
}

/**
 * 查询
 */
const onFetchData = () => {
  loading.value = true
  onFetch()
    .then(({ data }) => {
      data.items.forEach((v) => {
        if (v.set_json) {
          v.set_json_parse = JSON.parse(v.set_json)
          if (!v.set_json_parse.col) {
            v.set_json_parse.col = clone(defaultCol, true)
          }
        } else {
          v.set_json_parse = { props: {}, col: clone(defaultCol, true) }
        }
      })
      params.value = data
      if (data.type_name) checked.value = data.type_name
      // nextTick(() => {
      //   emit('preview')
      // })
    })
    .finally(() => (loading.value = false))
}

const onSave = async () => {
  const data = clone(unref(params), true)
  data.type_name = checked.value
  data.align = props.labelPosition || 'top'
  if (props.type === 'form') {
    return SaveBusinessUIForm(data)
  } else {
    return SaveBusinessUIQuery(data)
  }
}

/**
 * 保存UI
 */
const onSaveData = () => {
  loading.value = true
  onSave()
    .then(() => {
      ElMessage.success('保存成功')
    })
    .finally(() => (loading.value = false))
}

// json编辑指向组件
let openEditKey = 'Form'
/**
 * 编辑默认参数
 */
const openEditorDialog = async (parse?: any, key?: string) => {
  if (key) openEditKey = key
  editorRef.value.open(parse)
}

/**
 * 修改默认参数
 * @param value
 */
const onJsonChange = (value: TypedAny) => {
  if (openEditKey === 'Form') {
    params.value.default_value_parse = value || {}
  } else if (openEditKey) {
    const column = params.value.items.find((f) => f.field === openEditKey)
    if (column) {
      column.default_value_parse = value || {}
    }
  }
}

/**
 * 排序
 * @param index
 */
const onDeleteForm = (index: number) => {
  params.value.items.splice(index, 1)
}

/**
 * 选择组件
 * @param value
 * @param form
 */
const onSelectComponent = (value: string, form: BusinessUIQueryColumnType) => {
  const item = findTree(formComponents, (f) => f.value === value)
  if (item && item.item) {
    // 址引用，防止改原值
    const comp = clone(item.item, true)
    form.set_json_parse.props = comp.props
    form.set_json_parse.col = comp.col
  }
}

/**
 * 查询业务
 */
const onFetchBusiness = () => {
  GetBusinessTree().then(({ data }) => {
    businessItems.value = data
  })
}

/**
 * 是否是占位字段
 * @param form
 */
const isEmptyField = (form: BusinessUIQueryColumnType) => {
  return form.field.indexOf('empty_') !== -1
}

onMounted(() => {
  params.value.id = String(route.query.id || '')
  onFetchIFList()
  onFetchBusiness()
})

defineExpose({ params })
</script>

<template>
  <div class="system-dept-container layout-padding">
    <el-row class="h100">
      <el-col :xs="24" :sm="6" :md="6" :lg="4" :xl="4" class="flex flex-column mb5">
        <el-card shadow="hover" class="h100">
          <div class="h100 flex flex-column">
            <el-select v-model="checked" class="mb5 w100" filterable>
              <el-option
                v-for="(item, index) in list"
                :key="index"
                :value="item.type_name"
                :label="item.name"
              />
            </el-select>
            <div v-if="!columns.length">
              <el-skeleton />
              <el-skeleton />
              <el-skeleton />
            </div>
            <div class="flex-grow" style="position: relative; min-height: 200px">
              <el-input
                v-model="keywords"
                placeholder="关键字"
                :suffix-icon="Search"
                clearable
                class="mb5"
              />
              <el-scrollbar style="position: absolute">
                <div class="list-group">
                  <div
                    v-for="item in loopColumns"
                    :key="item.name"
                    class="list-group-item flex flex-shrink justify-between"
                    :class="{ active: isActive(item) }"
                  >
                    <div class="flex align-center">
                      <el-text>{{ item.name }}</el-text>
                    </div>
                    <el-button
                      :icon="Plus"
                      size="small"
                      circle
                      :disabled="isActive(item)"
                      @click="addFormColumn(item)"
                    />
                  </div>
                  <div class="list-group-item flex flex-shrink justify-between">
                    <div class="flex align-center">
                      <el-text>占位</el-text>
                    </div>
                    <el-button :icon="Plus" size="small" circle @click="addEmptyColumn" />
                  </div>
                  <div style="height: 50px; width: 100%"></div>
                </div>
              </el-scrollbar>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :xs="24" :sm="18" :md="18" :lg="20" :xl="20" class="h100 mb5">
        <el-card shadow="hover" class="mb5 ml5">
          <el-row>
            <!--            <el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="4">-->
            <!--              <el-tree-select-->
            <!--                v-model="params.id"-->
            <!--                filterable-->
            <!--                default-expand-all-->
            <!--                :data="businessItems"-->
            <!--                value-key="id"-->
            <!--                placeholder="选择业务"-->
            <!--                @change="onFetch"-->
            <!--                :props="{-->
            <!--                  label: 'title'-->
            <!--                }"-->
            <!--              />-->
            <!--            </el-col>-->
            <el-col :xs="24" :sm="14" :md="15" :lg="15" :xl="14">
              <div class="flex align-center">
                <el-checkbox v-model="isSort" label="排序模式" class="mr5" />
                <el-input v-model="params.api" placeholder="接口地址" clearable />
              </div>
            </el-col>
            <el-col :xs="24" :sm="10" :md="9" :lg="9" :xl="10">
              <div class="flex align-center flex-warp mr1">
                <el-button :icon="Refresh" @click="onFetchData" :loading="loading" class="ml-auto">
                  刷新
                </el-button>
                <el-button
                  type="warning"
                  :icon="Edit"
                  @click="openEditorDialog(undefined, 'Form')"
                  :loading="loading"
                  class="ml5"
                >
                  默认参数
                </el-button>
                <el-button
                  type="primary"
                  :icon="Edit"
                  @click="onSaveData"
                  :loading="loading"
                  class="ml5"
                >
                  保存配置
                </el-button>
              </div>
            </el-col>
            <!--            <el-col :xs="24" :sm="6" :md="6" :lg="4" :xl="4">-->
            <!--              <el-select v-model="params.method" class="mr5 flex-shrink" placeholder="请求方式" clearable-->
            <!--                         style="width: 100px">-->
            <!--                <el-option label="GET" value="get"/>-->
            <!--                <el-option label="POST" value="post"/>-->
            <!--                <el-option label="PUT" value="put"/>-->
            <!--                <el-option label="DELETE" value="delete"/>-->
            <!--              </el-select>-->
            <!--            </el-col>-->
          </el-row>
        </el-card>
        <div class="flex-grow ml5" style="position: relative; min-height: calc(100% - 70px)">
          <el-scrollbar noresize style="position: absolute" class="flex-grow">
            <slot name="view" />
            <QueryConfig
              v-if="params.items.length"
              v-show="!isSort"
              :params="params"
              :columns="columns"
              :business="businessItems"
              :on-edit-json="openEditorDialog"
              @remove="onDeleteForm"
              @select-component="onSelectComponent"
            />
            <el-empty v-if="!params.items.length" description="暂无数据，点击左侧添加吧" />
            <div v-else-if="isSort">
              <draggable
                v-model="params.items"
                group="column"
                item-key="name"
                :animation="300"
                class="table-group"
              >
                <template #item="{ element, index }">
                  <div class="flex align-center cursor-move pt5 pb5">
                    <el-icon>
                      <Rank />
                    </el-icon>
                    <el-icon v-if="isEmptyField(element)" size="16" class="ml5 mr5 color-primary">
                      <Warning />
                    </el-icon>
                    <span class="ml10" v-else :class="{ pl20: !isEmptyField(element) }"
                      >{{ index + 1 }}.
                    </span>
                    <span v-if="element.required" class="font-bold font20 color-danger mt5 ml3 mr3"
                      >*</span
                    >
                    <span>{{ element.title || element.field }}</span>
                  </div>
                </template>
              </draggable>
            </div>
          </el-scrollbar>
        </div>
      </el-col>
    </el-row>
    <JsonEditorDialog ref="editorRef" :params="params" @change="onJsonChange" />
  </div>
</template>

<style scoped lang="scss">
.table-group {
  list-style: none;
  min-height: 30px;
  min-width: 100%;

  .table-group-item {
    position: relative;
    padding: 2px 10px;
    margin-bottom: -1px;
    border: 1px solid var(--el-border-color);
    cursor: move;
    user-select: none;
    margin-right: 3px;
    border-radius: 3px;

    &.active {
      color: var(--el-color-primary);
      border-color: var(--el-color-primary);
    }
  }
}

.list-group {
  list-style: none;

  .list-group-item {
    position: relative;
    padding: 5px;
    margin-bottom: -1px;
    border: 1px solid var(--el-border-color);

    &.active {
      cursor: no-drop;
      opacity: 0.4;
    }
  }

  .list-group-item:first-child {
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
  }
}
</style>
